<?php


class sfCustomWidgetsActions extends sfActions
{
    public  $fk_model_list = null;


    public function preExecute(){
        sfContext::getInstance()->getConfiguration()->loadHelpers(array('I18N'));
    }

    public function executeCheck_user_unique(sfWebRequest $request){



        $model = $request->getParameter('model');
        $value = $request->getParameter('value');
        $column = $request->getParameter('column');
        $this->forward404Unless( $model && $value && $column );

        $c = new Criteria();
        $c->add(constant($model.'Peer::'.strtoupper($column)) , $value );

        $count = call_user_func_array(array($model.'Peer','doCount') , array($c) );

        if($count > 0 ){
            return $this->renderText('<span class="not_ok">'.__('This user is already in use').'</span>');
        }else{
            return $this->renderText('<span class="ok">'.__('User is available').'</span>');
        }

    }


    protected function getChoices( $this_model, $next_model = null, $this_value = null ){


        if(!$this_value){
            $objs = call_user_func_array(array($this_model.'Peer','doSelect'),array(new Criteria()));
        }else{
            $this_object = call_user_func_array( array($this_model.'Peer','retrieveByPK') , array($this_value) );
            //var_dump($this_model);exit;

            $objs = call_user_func(array($this_object,'get'.$next_model.'s'));
        }

        $arr_output = array();
        foreach ($objs as $obj){
            $arr_output[$obj->getId()] = $obj->__toString();
        }

        return $arr_output;


    }


    protected function getTreeData( $value , $fk_model_list) {

        $html_output = "";

        $fk_model_list_reversed =  array_reverse($fk_model_list);

        $f_values_reversed = array();
        $f_object_list_reversed = array();
        $this_value = $value;
        for( $i = 0 ; $i < count($fk_model_list_reversed) ; $i++ ) {
            //foreach ($fk_model_list_reversed as $fk_model){
            $this_model = sfInflector::camelize($fk_model_list_reversed[$i]);
            $next_model = !empty($fk_model_list_reversed[$i+1]) ? sfInflector::camelize($fk_model_list_reversed[$i+1]) : null;

            $obj = call_user_func_array(array($this_model.'Peer','retrieveByPK'),array($this_value));
            $f_values_reversed[] = $this_value;
            $f_object_list_reversed[] = $obj;

            //die($next_model);

            if($next_model){
                //die('get'.$next_model);
                $next_obj = call_user_func( array($obj,'get'.$next_model) );
                //var_dump($next_obj);exit;
                $this_value = $next_obj->getId();
            }
        }

        $f_object_list = array_reverse($f_object_list_reversed);


        $html_output = $this->darwRec( $f_object_list , $f_object_list[0]->getId() , $value , 0 );


        return $html_output;

    }

    protected function darwRec( $objs , $this_value , $widget_value , $depth = 0 ){
        $html_output  = "";
        $this_object  = $objs[$depth] ;

        $next_object  = !empty( $objs[$depth+1] ) ? $objs[ $depth + 1 ] : null ;
        $prev_object  = !empty( $objs[$depth-1] ) ? $objs[ $depth - 1 ] : null ;

        $parent_value = $prev_object ? $prev_object->getId() : "";

        if( $depth == 0 && $next_object ){

            $choices = $this->getChoices( get_class($this_object)  );

            foreach ( $choices as $k => $v ) {
                $ul_content = "";
                $class = "closed";
                if($this_value == $k){
                    $class = " open";
                    $ul_content = '<ul>'.chr(10).$this->darwRec( $objs , $next_object->getId() , $widget_value  , $depth + 1 ).'</ul>'.chr(10);
                }
                //$extra = " onclick='return tree_check(this)'";
                $extra = "";
                $html_output .= chr(10).$this->drawItem($this->fk_model_list , get_class($this_object) , $v , $k ,$class, $ul_content ,$extra, $parent_value).chr(10) ;
            }

        } elseif( $next_object ) {

            $choices = $this->getChoices( get_class($prev_object) , get_class($this_object) , $prev_object->getId() );
            foreach ( $choices as $k => $v ) {
                $ul_content = "" ;
                $class = "closed";
                if( $this_value == $k ) {
                    $class = " open";
                    $ul_content = '<ul>'.chr(10).$this->darwRec( $objs , $next_object->getId() , $widget_value  , $depth + 1 ).'</ul>'.chr(10);
                }
                //$extra = " onclick='return tree_check(this)'";
                $extra = "";
                $html_output .= chr(10).$this->drawItem( $this->fk_model_list , get_class($this_object) , $v , $k ,$class, $ul_content,$extra, $parent_value ).chr(10) ;
            }

        }else{

            $choices = $this->getChoices( get_class($prev_object) , get_class($this_object) , $prev_object->getId() );
            foreach ($choices as $k => $v){
                $class = "closed last-level";
                if( $this_value == $k ){
                    $class .= " checked";
                }
                //$extra = " onclick='return tree_check(this)'";
                $extra = "";
                $html_output .= chr(10).$this->drawItem( $this->fk_model_list , get_class($this_object) , $v , $k ,$class , "",$extra, $parent_value).chr(10) ;
            }
        }
        return $html_output;


    }

    public function executeBind_ajax_tree(sfWebRequest $request)
    {
        $value = $request->getParameter('value' ,null);
        $fk_model_list_serialized = $request->getParameter('fk_model_list' ,null);

        if( !$fk_model_list_serialized ){
            $this->forward404('missing values in get request');
        }

        $this->fk_model_list = $fk_model_list = unserialize($fk_model_list_serialized);

        $id_struct = $request->getParameter( 'id' , null );

        $this_model = $next_model = "";
        if($id_struct){
            $arr2 = json_decode(urldecode($id_struct),1);
            $this_model = !empty($arr2['this_model']) ? $arr2['this_model'] : '' ;
            $next_model = !empty($arr2['next_model']) ? $arr2['next_model'] : '' ;
            $this_value = !empty($arr2['this_value']) ? $arr2['this_value'] : '' ;
        }


        if( $id_struct || !$value ) {
            //$html = "<ul class='ltr'>";

            //{$this_model_value}{$this_model_text}{$next_model_text}
            $first_model  = sfInflector::camelize( $fk_model_list[0] );
            $second_model = sfInflector::camelize( $fk_model_list[1] );


            $this_model =  !empty($this_model) ? $this_model : sfInflector::camelize( $first_model  );
            $next_model =  !empty($next_model) ? $next_model : sfInflector::camelize( $second_model );
            $this_value =  !empty($this_value) ? $this_value : null;


            $html = "";
            $parent_value = $this_value ? $this_value : '';
            foreach ( $this->getChoices( $this_model , $next_model , $this_value ) as $k => $v ) {
                //echo($next_model);
                //die(sfInflector::camelize($this->fk_model_list[count($this->fk_model_list)-1]));
                $last_leaf = ( $next_model == sfInflector::camelize($this->fk_model_list[count($this->fk_model_list)-1]) && $this_value ) || $this_model == sfInflector::camelize($this->fk_model_list[count($this->fk_model_list)-1]);
                $class = 'closed';
                $class .= $last_leaf ? " last-level" : '';
                //$extra = " onclick='return tree_check(this)'" ;
                $extra = "" ;
                $html .= $this->drawItem($fk_model_list , !$this_value ? $this_model : $next_model , $v , $k , $class,'',$extra , $parent_value);
                //die($parent_value);

            }
            //$html.="</ul>";
            $html.="";
        } else {
            //'?model=%s&pk=%s&peer_method=%s&fk=%s&add_empty=%s&fk_value=',$this->getOption('model'),$this->getOption('pk'),$this->getOption('peer_method'),$fk,$add_empty
            $html = $this->getTreeData( $value , $fk_model_list );
        }


        return $this->renderText($html);

    }

    protected function drawItem( $fk_model_list , $this_model , $lable , $this_value, $class = 'closed' , $ul_content = "",$extra="",$parent_value=""){
        $html = "";

        $json_data_id = $this->getJsonId( $fk_model_list , $this_model , $this_value );

        $arr = json_decode(urldecode($json_data_id),1);
        $class .= !empty( $arr['next_model'] ) ? '' : ' leaf';

        //$root_leaf =  $this_model == sfInflector::camelize($this->fk_model_list[0]);
        $index  = array_search( sfInflector::underscore($this_model) , $fk_model_list );
        $parent = !empty($fk_model_list[$index - 1]) && $parent_value ? "parent='".$fk_model_list[$index - 1]."_{$parent_value}'" : '';
        $value  = !empty($this_value) ? "value='".$this_value."'" : '';
        $html_id = $value ? "id='".sfInflector::underscore($this_model)."_{$this_value}'" : '';
        $inflated_params = "{$parent} {$html_id} $value";

        $html .= "<li {$inflated_params} {$extra} struct='{$json_data_id}' class='{$class}'><a href='#'  onclick='return tree_check(this);' ><ins>&nbsp;</ins>".$lable."</a>".$ul_content."</li>";
        return $html;
    }

    protected function getJsonId( $fk_model_list , $this_model , $this_value ){
        $arr['this_value'] = $this_value;
        $arr['this_model'] = $this_model;
        $next_index = array_search( sfInflector::underscore($arr['this_model']) , $fk_model_list ) + 1;

        $arr['next_model'] = !empty($fk_model_list[$next_index]) ? sfInflector::camelize($fk_model_list[$next_index]) : null;
        return urlencode(json_encode( $arr ));
    }

    public function executeBind_ajax(sfWebRequest $request)
    {
        $this->forward404Unless($model = $request->getParameter('model'),'model is not set');
        $this->forward404Unless($fk_value = $request->getParameter('fk_value'),'fk_value is not set');
        $this->forward404Unless($fk_column = $request->getParameter('fk'),'fk value is not existed');


        $add_empty = $request->getParameter('add_empty');
        $add_empty = !empty($add_empty) ? $add_empty : false;


        $peer_method = $request->getParameter('peer_method');
        $peer_method = !empty($peer_method) ? $peer_method : 'doSelect';


        $pk_column = $request->getParameter('pk');
        $pk_column = !empty($pk_column) ? $pk_column : 'id';


        $key_method = $request->getParameter('key_method');
        $key_method = !empty($key_method) ? $key_method : 'get'.ucfirst($pk_column);


        $method = $request->getParameter('method');
        $method = !empty($method) ? $method : '__toString';


        $fk_value_arr = array();
        $tmp = explode(',',$fk_value);
        if(!is_array($tmp) || count($tmp) <=0 ){
            $fk_value_arr = array($fk_value);
        }else{
            $fk_value_arr = $tmp;
        }
        //var_dump($fk_value_arr);exit;

        $model_peer = $model.'Peer';

        $callable_arr = array($model_peer, $peer_method);
        /*
        if(class_exists($model)){
        throw new Exception(sprintf('Class ( %s ) is not existed',$model));
        }*/

        if(!is_callable($callable_arr)){
            throw new Exception(sprintf('Method ( %s ) is not existed',$peer_method));
        }

        $c= new Criteria();


        //var_dump($model_peer.'::'.strtoupper($fk_column));exit;
        $c->add(constant($model_peer.'::'.strtoupper($fk_column)),$fk_value_arr,Criteria::IN );


        $objs = call_user_func_array($callable_arr,array($c));

        $html = "";
        $first_child = !empty($add_empty) ? '<option value="" class="empty">'.(is_string($add_empty) ? $add_empty : '').'</option>' : null;
        foreach ( $objs as $obj ) {

            if( !method_exists( $obj ,$key_method ) ) {
                throw new Exception(sprintf('Method ( %s ) is not implemented for class %s',$key_method,get_class($obj)));
            }
            if( !method_exists($obj ,$method) ) {
                throw new Exception(sprintf('Method ( '.$method.' ) is not implemented for class %s',get_class($obj)));
            }

            $id = call_user_func_array(array($obj,$key_method),array());
            $value = call_user_func_array(array($obj,$method),array());


            $html .= sprintf("<option value='%d'>%s</option>",$id ,$value);

        }

        return $this->renderText($first_child.$html);
    }

}
